//
//  IOPackSerialController.java
//  SketchServer
//
//  Created by Brian Hinch on 9/4/08.
//  Copyright 2008 Tellart. All rights reserved.
//

import java.io.*;
import java.lang.*;
import java.math.*;

//import javax.comm.*;
import gnu.io.*;
//import Serialio.SerialPortLocal;

import java.util.TooManyListenersException;

public class IOPackSerialController extends SketchProtocolTransport implements SerialPortEventListener {

    public static final String DISABLED_INTERFACE = "(disable)";
    

    public static final int PORT_OPEN_TIMEOUT = 100;
    
    /***********************************/
    
    private boolean started = false;
    
	private CommPortIdentifier myPortID;
	private SerialPort myPort = null;

    public IOPackSerialController(int code, SketchProtocolListener lsnr) {
        super(code, lsnr);
    }

    /*
     * starts the controller
     *
     */
    public void start(String portName) throws UnsupportedCommOperationException, AlreadyStartedException, NoSuchPortException, TooManyListenersException, PortInUseException, IOException  {
        if (started) throw new AlreadyStartedException();
        if (portName.toLowerCase().equals(IOPackSerialController.DISABLED_INTERFACE)) return;
        
		//try to get a CommPortIdentifier
		myPortID = CommPortIdentifier.getPortIdentifier(portName);
        openPort();

        started = true;
    } //start
    
    /*
     * stops the controller
     *
     */
    public void stop() {
        if (!started) return;
        closePort();
        started = false;
    } //stop
    
	private void openPort() throws IOException, TooManyListenersException, PortInUseException, UnsupportedCommOperationException {
		System.out.println("IOPackSerialController: opening port...");
        myPort = (SerialPort) myPortID.open("IOPackSerialController", PORT_OPEN_TIMEOUT);
        //get streams
        
        synchronized (myPort) {
            //configure the port
            myPort.setSerialPortParams(9600, 
                          SerialPort.DATABITS_8, 
                          SerialPort.STOPBITS_1, 
                          SerialPort.PARITY_NONE);
            
            myPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE | SerialPort.FLOWCONTROL_NONE);
        
            //set up notifications
            myPort.notifyOnBreakInterrupt(true);
            myPort.notifyOnCarrierDetect(true);
            myPort.notifyOnCTS(true);
            myPort.notifyOnDataAvailable(true);
            myPort.notifyOnDSR(true);
            myPort.notifyOnFramingError(true);
            myPort.notifyOnOutputEmpty(true);
            myPort.notifyOnOverrunError(true);
            myPort.notifyOnParityError(true);
            myPort.notifyOnRingIndicator(true);
            //add listener
            myPort.addEventListener(this);
            
            //set up the I/O streams (this goes to the SketchProtocolTransport
            setIOStreams(myPort.getInputStream(), myPort.getOutputStream());
        }
		if (myPort == null) {
			System.err.println("IOPackSerialController: open port FAILED");
		} else {
			System.out.println("IOPackSerialController: open port SUCCEEDED");
		}
	} //openPort
	
	/**
	 * close the port
	 *
	 */
	private void closePort() {
		System.out.println("IOPackSerialController: closing port");
		if (myPort == null) return;
		try {
			myPort.close();
		} catch (Exception e) { }
		myPort = null;
        setIOStreams(null, null);
	} //closePort

    public boolean isStarted() {
        return started;
    } //isStarted

	/**
	 * from SerialPortEventListener
	 *
	 */
	public void serialEvent(SerialPortEvent ev) {
        //System.out.println("IOPackSerialController.serialEvent: " +  ev.getEventType());
        //System.out.println(ev);
        
		switch (ev.getEventType()) {
			case SerialPortEvent.DATA_AVAILABLE:
				//new data
                readInputBuffer();
			break;
			case SerialPortEvent.BI:
				//break interrupt
			break;
			case SerialPortEvent.CD:
				//carrier detect
			break;
			case SerialPortEvent.CTS:
				//clear to send
			break;
			case SerialPortEvent.DSR:
				//data set ready
			break;
			case SerialPortEvent.FE:
				//framing error
			break;
			case SerialPortEvent.OE:
				//overrun error
			break;
			case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
				//output buffer is empty
			break;
			case SerialPortEvent.PE:
				//parity error
			break;
			case SerialPortEvent.RI:
				//ring indicator
			break;
		}
    } //serialEvent

} //class

